package com.hdu;

import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

/**
 * 请求执行器 , 可以给请求设置超时时间 如果超时未完成 那么返回设置的默认结果
 */
public class RequestExecutor {


    private static final SystemTimer timer = TimerFactory.createSystemTimer(
            "doRequest",
            200,
            TimeUnit.MILLISECONDS,
            5
    );

    private static ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "doRequest");
        }
    });

    /**
     * 同步调用
     *
     * @param supplier      执行逻辑
     * @param timeout       超时时间
     * @param timeUnit      超时时间单位
     * @param defaultResult 默认返回结果
     * @param <T>
     * @return
     */
    public static <T> T doRequestSync(Supplier<T> supplier,
                                      long timeout, TimeUnit timeUnit,
                                      T defaultResult) {
        // 1. 包装原始执行逻辑 + 添加回调逻辑
        EnhanceFutureTask<T> enhanceFutureTask = EnhanceFutureTask.of(
                () -> {
                    try {
                        return supplier.get();
                    } catch (Exception e) {
                        return defaultResult;
                    }
                }
        );
        // 2. 提交延迟任务到时间轮, 超时返回默认返回结果
        TimerTask timerTask = new TimerTask(timeout, timeUnit) {
            @Override
            public void run() {
                enhanceFutureTask.set(defaultResult);
            }
        };
        timer.add(timerTask);
        try {
            executorService.submit(enhanceFutureTask);
            return enhanceFutureTask.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 异步调用
     *
     * @param supplier      执行逻辑
     * @param callback      回调逻辑
     * @param timeout       超时时间
     * @param timeUnit      超时时间单位
     * @param defaultResult 默认返回结果
     * @param <T>
     */
    public static <T> void doRequestAsync(Supplier<T> supplier,
                                          BiConsumer<T, Throwable> callback,
                                          long timeout, TimeUnit timeUnit,
                                          T defaultResult) {
        // 1. 包装原始执行逻辑 + 添加回调逻辑
        EnhanceFutureTask<T> enhanceFutureTask = EnhanceFutureTask
                .of(
                        () -> {
                            try {
                                return supplier.get();
                            } catch (Exception e) {
                                throw e;
                            }
                        }
                ).addFinallyListener(
                        (futureTask) -> {
                            callback.accept(futureTask.getResult(), futureTask.getException());
                        }
                );
        // 2. 提交延迟任务到时间轮, 超时返回默认返回结果
        timer.add(
                new TimerTask(timeout, timeUnit) {
                    @Override
                    public void run() {
                        enhanceFutureTask.set(defaultResult);
                    }
                }
        );
        executorService.submit(enhanceFutureTask);
    }

}
